package com.authine.cloudpivot.ext.util;


import com.alibaba.cola.exception.BizException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.authine.common.json.JsonUtils;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.dto.errorcode.ErrorCodeEnum;
import com.authine.mvp.app.org.dto.domainvo.DeptOrUserVO;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class BoUtils {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final ObjectMapper objectMapper2 = new ObjectMapper();

    static {
        init(objectMapper);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        init(objectMapper2);
        objectMapper2.setSerializationInclusion(JsonInclude.Include.ALWAYS);
    }

    public static Map<String, Object> objectToMap(Object obj)   {
        Map<String, Object> map = new HashMap<>();
        try {
            Class<?> clazz = obj.getClass();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(obj);
                map.put(fieldName, value);

            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
     return map;
    }

    private static void init(ObjectMapper objectMapper){
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        String timeZone = StringUtils.isBlank((timeZone = System.getProperty("user.timezone", "Asia/Shanghai"))) ? "Asia/Shanghai" : timeZone;
        objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone));

        //只有不为null的字段才被序列化
        //objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //如果是空对象的时候,不抛异常
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    public static Map<String, Object> bo2Map(Object obj){
        Map<String, Object> map;
        try {
            map = objectMapper.readValue(objectMapper.writeValueAsString(obj), new TypeReference<Map<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw bizException(e.getMessage());
        }
        return map;
    }

    public static Map<String, Object> bo2MapAllowNull(Object obj){
        Map<String, Object> map;
        try {
            map = objectMapper2.readValue(objectMapper2.writeValueAsString(obj), new TypeReference<Map<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw bizException(e.getMessage());
        }
        return map;
    }

    public static <T> T Map2Bo(Map<String, Object> map, Class<T> clazz){
        T t;
        try {
            t = objectMapper.readValue(objectMapper.writeValueAsString(map), clazz);
        } catch (JsonProcessingException e) {
            throw bizException(e.getMessage());
        }
        return t;
    }

    public static <T> T json2Object(String json, Class<T> clazz){
        T t;
        try {
            t = objectMapper.readValue(json, clazz);
        } catch (Exception e) {
            throw bizException(e.getMessage());
        }
        return t;
    }

    public static String toJsonString(Object obj){
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T copy2Class(Object source, Class<T> clazz){
        try {
            return objectMapper.readValue(toJsonString(source),clazz);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> List<T> copy2List(Object source, Class<T> clazz){
        try {
            TypeFactory typeFactory = objectMapper.getTypeFactory();
            return objectMapper.readValue(toJsonString(source), typeFactory.constructCollectionLikeType(List.class, clazz));
            //return objectMapper.readValue(toJsonString(source), new TypeReference<List<T>>() {});
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    public static String getOrgId(Object org){
        if (org == null) {
            return null;
        }
        if (org instanceof String) {
            if (((String) org).startsWith("{")) {
                try {
                    return objectMapper.readValue((String) org, JsonNode.class).get("id").asText();
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                return null;
            }
            if (((String) org).startsWith("[")) {
                try {
                    return objectMapper.readValue((String) org, new TypeReference<JsonNode>() {}).get(0).get("id").asText();
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                return null;
            }
            return (String) org;
        }
        if (org instanceof DeptOrUserVO) {
            return ((DeptOrUserVO) org).getId();
        }
        if(org instanceof SelectorFormat){
            return ((SelectorFormat) org).getId();
        }
        if(org instanceof Map){
            return (String) ((Map) org).get("id");
        }
        try {
            return String.valueOf(FieldUtils.readField(org, "id"));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getSelectId(Object org) {
        if(org instanceof List && ((List<String>) org).get(0).indexOf("\"id\"") > 0){
            SelectorFormat selectorFormat = JsonUtils.toObject(((List<String>) org).get(0), SelectorFormat.class);
            return selectorFormat.getId();
        }
        return null;
    }

    public static BizException bizException(String errorMessage){
        ErrorCodeEnum bizError = ErrorCodeEnum.BIZ_EXCEPTION;
        bizError.setErrDesc(errorMessage);
        return new BizException(bizError,errorMessage);
    }

    /**
     * 1. 数组格式的对象 直接转对象返回；
     * 2. 对象格式 直接返回
     * 3. 字符串格式 直接返回
     * @param obj
     * @return
     */
    public static Object getValue(Object obj){
        if(obj instanceof String){
            return obj;
        }
        if(isJsonArray(JSON.toJSONString(obj))){
            List<Object> objs = (List<Object>) obj;
            if(objs.size() == 0){
                return null;
            }
            return objs.get(0);
        }
        return obj;
    }

    /**
     * 判断字符串是否可以转化为JSON数组
     *
     * @param content
     * @return
     */
    public static boolean isJsonArray(String content) {
        if (org.apache.commons.lang.StringUtils.isBlank(content)) {
            return false;
        }
        org.apache.commons.lang.StringUtils.isEmpty(content);
        try {
            JSONArray.parseArray(content);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static BigDecimal getBigDecimal(Object value) {
        if(value==null){
            return new BigDecimal(0);
        }
        if(value instanceof BigDecimal){
            return (BigDecimal) value;
        }
        try {
            BigDecimal bigDecimal = new BigDecimal(value.toString());
            return bigDecimal;
        } catch (Exception e) {
            log.error("getBigDecimal exception",e);
        }
        return new BigDecimal(0);
    }

    public static String getId(Object value) {
        if(value==null){
            return null;
        }
        if(value instanceof String){
            return (String) value;
        }
        if(value instanceof Map){
            return getId(((Map) value).get("id"));
        }
        return value.toString();
    }

    public static SelectorFormat DeptOrUserVOTOSelectorFormat(Object value){
        DeptOrUserVO deptOrUserVO = (DeptOrUserVO) value;
        SelectorFormat selectorFormat = new SelectorFormat();
        if(null != deptOrUserVO) {
            selectorFormat.setId(deptOrUserVO.getId());
            selectorFormat.setName(deptOrUserVO.getName());
            selectorFormat.setType(deptOrUserVO.getType().getIndex());
        }
        return selectorFormat;
    }

    public static Date dateFormat(String dateFormat){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        try {
            return simpleDateFormat.parse(dateFormat);
        } catch (ParseException e) {
            throw new BizException("时间格式化失败");
        }
    }
}
